/*
    Copyright 2006 Andrew Wilkinson <andrew@indiegigs.co.uk>

    This file is part of GL2x.

    GL2x is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    GL2x is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with GL2x; if not, write to the Free Software
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/

#include <stdlib.h>

#include "driver.h"

/* This file is included in render.c and does not need to be compiled seperately. */

unsigned char GL2x_drv_line_r = 255;
unsigned char GL2x_drv_line_g = 255;
unsigned char GL2x_drv_line_b = 255;
unsigned char GL2x_drv_line_a = 255;

void GL2x_drawline(int x0, int x1, int y0, int y1, void (*putpixelfunc)(int, int, int, Vector), Vector c0, Vector c1) {
    int dx = x1 - x0;
    int dy = y1 - y0;

    if(dx == 0) {
        int step = (dy < 0) ? -1 : 1;
        Vector dc = Vector_sub(c1, c0);
        dc = Vector_divi(dc, dy);
        while(y0 != y1) {
            putpixelfunc(x0, y0, 1, c0);
            y0 = y0 + step;
            c0 = Vector_add(c0, dc);
        }
    } else if(dy == 0) {
        int step = (dx < 0) ? -1 : 1;
        Vector dc = Vector_sub(c1, c0);
        dc = Vector_divi(dc, dx);
        while(x0 != x1) {
            x0 = x0 + step;
            c0 = Vector_add(c0, dc);
            putpixelfunc(x0, y0, 0, c0);
        }
    } if(abs(dx) > abs(dy)) {
        Fixed m = Fixed_divi(Fixed_createi(dy), dx);
        Fixed b = Fixed_sub(Fixed_createi(y0), Fixed_muli(m, x0));
        Vector dc = Vector_sub(c1, c0);
        dc = Vector_divi(dc, dx);
        dx = (dx < 0) ? -1 : 1;
        while(x0 != x1) {
            putpixelfunc(x0, Fixed_round(Fixed_add(Fixed_muli(m, x0), b)), 0, c0);
            x0 += dx;
            c0 = Vector_add(c0, dc);
        }
    } else if(dy != 0) {
        Fixed m = Fixed_divi(Fixed_createi(dx), dy);
        Fixed b = Fixed_sub(Fixed_createi(x0), Fixed_muli(m, y0));
        Vector dc = Vector_sub(c1, c0);
        dc = Vector_divi(dc, dy);
        dy = (dy < 0) ? -1 : 1;
        while(y0 != y1) {
            putpixelfunc(Fixed_round(Fixed_add(Fixed_muli(m, y0), b)), y0, 1, c0);
            y0 += dy;
            c0 = Vector_add(c0, dc);
        }
    }
}

#define makechar(x) ((unsigned char)Fixed_round(Fixed_muli(x, 255)))

void GL2x_putsinglepixel(int x, int y, int a, Vector c) {
    GP2x_putPixel(x, y, makechar(c.r), makechar(c.g), makechar(c.b), makechar(c.a));
}

void GL2x_putsquarepixel(int x, int y, int a, Vector c) {
    int i;
    int lw = Fixed_round(Fixed_divi(line_width, 2));
    switch(a) {
    case 0:
        for(i=y-lw; i<y+lw; i++) {
            GP2x_putPixel(x, i, makechar(c.r), makechar(c.g), makechar(c.b), makechar(c.a));
        }
        break;
    case 1:
        for(i=x-lw; i<x+lw; i++) {
            GP2x_putPixel(i, y, makechar(c.r), makechar(c.g), makechar(c.b), makechar(c.a));
        }
        break;
    }
}

void GL2x_renderline(Vector v1, Vector v2, Vector c1, Vector c2) {
    if(Fixed_eq(line_width, Fixed_one)) {
        int v1x = Fixed_round(v1.x); int v1y = Fixed_round(v1.y);
        int v2x = Fixed_round(v2.x); int v2y = Fixed_round(v2.y);

        GL2x_drawline(v1x, v2x, v1y, v2y, GL2x_putsinglepixel, c1, c2);
    } else {
        int v1x = Fixed_round(v1.x); int v1y = Fixed_round(v1.y);
        int v2x = Fixed_round(v2.x); int v2y = Fixed_round(v2.y);

        GL2x_drawline(v1x, v2x, v1y, v2y, GL2x_putsquarepixel, c1, c2);
    }

}
